#include <ctime>
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
#include <climits>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <cerrno>
#include <algorithm>

/* --------------------------------------------- */

struct dat_t
{
  static const size_t HSZ0 = 64; // SHA3512 = 64 bytes
  void* p; // position
  size_t b; // bytes
  dat_t(const size_t& bytes = 0) : p(NULL), b(bytes) {}
  dat_t(void* position, const size_t& bytes) : p(position), b(bytes) {}
  inline void init_(const size_t& bytes = 0) { p = NULL; b = bytes; }
  inline void init_(void* position, const size_t bytes)
  {
    p = position;
    b = bytes;
  }
  inline void init_(const dat_t& dat)
  {
    p = dat.p;
    b = dat.b;
  }
  inline void fina_()
  {
    if (p)
    {
      free(p);
      p = NULL;
    }
  }
  inline short get_(const char* filename, const size_t offset = 0, size_t bytes = 0) // temporal O(1)
  {
    if (!p) return 1;
    int fd1 = open(filename, O_RDONLY);
    if (fd1 < 0)
    {
      perror("dat_t.get_(): ---open---");
      return -1;
    }
    flock(fd1, LOCK_SH);
    struct stat fs1;
    if (fstat(fd1, &fs1) < 0)
    {
      perror("dat_t.get_(): ---fstat---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -2;
    }
    size_t fb1 = (size_t)fs1.st_size;
    if (offset > fb1)
    {
      fprintf(stderr, "dat_t.get_(): Read initial exceeds file bytes.\n");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -3;
    }
    size_t maxbyte = fb1 - offset;
    if (bytes == 0 || bytes > maxbyte) bytes = maxbyte;
    if (bytes > b)
    {
      fprintf(stderr, "dat_t.get_(): Read range exceeds buffer bytes.\n");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -4;
    }
    if (pread(fd1, p, bytes, offset) < 0)
    {
      perror("dat_t.get_(): ---pread---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -5;
    }
    flock(fd1, LOCK_UN);
    close(fd1);
    return 0;
  }
  inline short put_(const char* filename, size_t offset = 0, size_t bytes = 0) // temporal O(1)
  {
    if (!p) return 1;
    int fd1 = open(filename, O_WRONLY | O_CREAT, 0644);
    if (fd1 < 0)
    {
      perror("dat_t.put_(): ---open---");
      return -1;
    }
    flock(fd1, LOCK_EX);
    struct stat fs1;
    if (fstat(fd1, &fs1) < 0)
    {
      perror("dat_t.put_(): ---fstat---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -2;
    }
    size_t fb1 = (size_t)fs1.st_size;
    if (offset > fb1) offset = fb1;
    if (lseek(fd1, offset, SEEK_SET) < 0)
    {
      perror("dat_t.put_(): ---lseek---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -3;
    }
    if (bytes == 0 || bytes > b) bytes = b;
    if (write(fd1, p, bytes) < 0)
    {
      perror("dat_t.put_(): ---write---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -4;
    }
    if (fsync(fd1) < 0)
    {
      perror("dat_t.put_(): ---fsync---");
      flock(fd1, LOCK_UN);
      close(fd1);
      return -5;
    }
    flock(fd1, LOCK_UN);
    close(fd1);
    return 0;
  }
  inline short app_(const char* filename, size_t bytes = 0)
  {
    return put_(filename, SIZE_MAX, bytes);
  }
  inline short new_(const char* filename, size_t bytes = 0)
  {
    unlink(filename);
    return put_(filename, 0, bytes);
  }
  inline size_t size_() const
  {
    if (!p) return 0;
    return 8 + b;
  }
  inline size_t serialize_(void* buffer) const
  {
    if (!p) return 0;
    uint8_t* ptr = static_cast<uint8_t*>(buffer);
    uint64_t b64 = b;
    for (int i = 0; i < 8; ++i)
      ptr[i] = (b64 >> (56 - i * 8)) & 0xFF;
    ptr += 8;
    memcpy(ptr, p, b);
    return 8 + b;
  }
  inline size_t deserialize_(const void* buffer)
  {
    if (!p) return 0;
    const uint8_t* ptr = static_cast<const uint8_t*>(buffer);
    uint64_t b64 = 0;
    for (int i = 0; i < 8; ++i)
      b64 |= (uint64_t)((unsigned char)(ptr[i])) << (56 - i * 8);
    b = b64;
    ptr += 8;
    memcpy(p, ptr, b);
    return b;
  }
};
